package com.ji.protobuf;

import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtostuffIOUtil;
import com.dyuproject.protostuff.Schema;
import com.dyuproject.protostuff.runtime.RuntimeSchema;
import com.google.common.io.Files;
import com.ji.module.Person;
import com.ji.module.PersonalSchool;
import com.ji.module.School;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;


//循环依赖无法解决
//支持 类属性增量
//支持 子类
//RuntimeSchema.getSchema 自带缓存 解决了耗时问题
public class ProtoTool {

//    private static final Objenesis OBJENESIS_STD = new ObjenesisStd(true);

    /**
     * 序列化对象
     *
     * @param obj 需要序更列化的对象
     * @return byte []
     */
    public static byte[] serialize(Object obj) {
        Class cls = obj.getClass();
        LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        try {
            long a = System.currentTimeMillis();
            Schema schema = RuntimeSchema.getSchema(cls);
            System.out.println(System.currentTimeMillis() - a);

            ProtostuffIOUtil.writeTo(outputStream, obj, schema, buffer);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        } finally {
            buffer.clear();
        }
        return outputStream.toByteArray();
    }

    /**
     * 反序列化对象
     *
     * @param param 需要反序列化的byte []
     * @param clazz
     * @return 对象
     */
    public static <T> T deSerialize(byte[] param, Class<T> clazz) {
        T object;
        try {
            ByteArrayInputStream inputStream = new ByteArrayInputStream(param);
            long a = System.currentTimeMillis();
            Schema schema = RuntimeSchema.getSchema(clazz);
            System.out.println(System.currentTimeMillis() - a);
            object = (T) schema.newMessage();
            ProtostuffIOUtil.mergeFrom(inputStream, object, schema);
            return object;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    public static void main(String[] args) throws IOException {
        School school = new School();
        school.setAddress("南京");
        school.setName("南大");
        Person person = new Person(21, "小王");
        Person person2 = new Person(22, "小李");
//         person.setSchool(school);
//         person2.setSchool(school);
        //循环依赖无法解决
        //支持 类属性增量
        //支持 子类
        List<Person> list = new ArrayList<>();
        list.add(person);
        list.add(person2);
        school.setStudents(list);
        byte[] bytes = ProtoTool.serialize(school);
        Files.write(bytes, new File("E://pro.data"));
        School s = ProtoTool.deSerialize(Files.toByteArray(new File("E://pro.data")), PersonalSchool.class);
        System.out.println(s);
    }
}
